#include "minecraftalgorthm.h"
#include "minecraftscenegeometry.h"
#include "minecraftblocklibrary.h"

MineCraftSceneGeometry::MineCraftSceneGeometry(QQuick3DObject *parent)
{

}

MineCraftSceneData *MineCraftSceneGeometry::scene() const
{
    return m_scene;
}

void MineCraftSceneGeometry::setScene(MineCraftSceneData *newScene)
{
    if (m_scene == newScene)
        return;
    m_scene = newScene;
    validate();
    emit sceneChanged();
}

void MineCraftSceneGeometry::rebuild()
{
    clear();

    int stride = 3 * sizeof(float) + 2 * sizeof(float);
    QByteArray vertexData;
    buildScene(vertexData);

    setVertexData(vertexData);
    setStride(stride);

    if(m_scene)
    {
        setBounds(QVector3D(0,0,0),m_scene->extend() * 100);
    }
    else{
        setBounds(QVector3D(0,0,0),QVector3D(0,0,0));
    }

    setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
    addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,0,QQuick3DGeometry::Attribute::F32Type);
    addAttribute(QQuick3DGeometry::Attribute::TexCoordSemantic,3 * sizeof(float),QQuick3DGeometry::Attribute::F32Type);
}

//是否需要过滤掉某个面
static inline bool filterFace(MineCraftSceneData* scene,int x,int y,int z){
    auto block = scene->get(x,y,z);
    if(!block)
    {
        return true;
    }
    if(block->type == BlockMeta::None)
    {
        return true;
    }

    BlockMeta *meta = MineCraftBlockLibrary::instance()->getBlock(block->type);
    auto attri = meta->attribute();
    if(attri & BlockMeta::BlockShape && !(attri & BlockMeta::Transparent))//当相邻方块是是不透明立方体时，这个面就会被剔除
    {
        return false;
    }
    return true;
}

void MineCraftSceneGeometry::buildScene(QByteArray &out)
{
    if(!m_scene)
    {
        return;
    }
    auto extend = m_scene->extend();
    for(int x = 0;x < extend.x();x++)
    {
        for(int y = 0;y < extend.y();y++)
        {
            for(int z = 0;z < extend.z();z++)
            {
                auto block = m_scene->get(x,y,z);
                if(!block) continue;

                if(block->type == BlockMeta::None)
                {
                    continue;
                }

                auto meta = MineCraftBlockLibrary::instance()->getBlock(block->type);
                auto attri = meta->attribute();
                if(attri & BlockMeta::BlockShape)
                {
                    //这个方块是立方体形状的
                    int direction  =MineCraftAlgorthm::None;

                    //剔除掉不该显示的面
                    if(filterFace(m_scene,x,y + 1,z))
                    {
                        direction |= MineCraftAlgorthm::Up;
                    }

                    if(filterFace(m_scene,x,y - 1,z))
                    {
                        direction |= MineCraftAlgorthm::Down;
                    }

                    if(filterFace(m_scene,x - 1,y,z))
                    {
                        direction |= MineCraftAlgorthm::Left;
                    }

                    if(filterFace(m_scene,x + 1,y,z))
                    {
                        direction |= MineCraftAlgorthm::Right;
                    }

                    if(filterFace(m_scene,x,y,z - 1))
                    {
                        direction |= MineCraftAlgorthm::Behind;
                    }

                    if(filterFace(m_scene,x,y,z + 1))
                    {
                        direction |= MineCraftAlgorthm::Front;
                    }

                    if(direction == MineCraftAlgorthm::None)//没有面可以显示，直接剔除整个方块
                    {
                        continue;
                    }

                    auto faces = meta->faces();

                    QVector3D position(x + 0.5,y + 0.5,z + 0.5);
                    position *= 100;
                    MineCraftAlgorthm::genMineCraftBlock(out,position,faces,(MineCraftAlgorthm::Direction)direction);
                }
                else{
                    //这个方块是非立方体形状的，需要读取mesh文件
                    QMatrix4x4 mat;
                    QVector3D position(x + 0.5,y + 0.5,z + 0.5);
                    position *= 100;
                    mat.translate(position);
                    mat.rotate(QQuaternion::fromEulerAngles(block->rotation));
                    MineCraftAlgorthm::createMeshBlock(out,meta->mesh(),mat);
                }
            }
        }
    }
}

void MineCraftSceneGeometry::validate()
{
    if(m_connection)
    {
        delete m_connection;
        m_connection = nullptr;
    }

    if(m_scene)
    {
        m_connection = new QObject(this);
        connect(m_scene,&MineCraftSceneData::buildFinished,m_connection,[=](){
            rebuild();
        });
    }

    rebuild();
}
